﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace BCCommon
{
    /// <summary>
    /// Redis缓存管理服务
    /// </summary>
    [NonInjection]
    public interface IRedisService:IDisposable
    {
        /// <summary>
        /// 是否存在Redis服务器
        /// </summary>
        bool ServerExists { get; set; }
        /// <summary>
        /// 拼接方法参数及方法请求值
        /// </summary>
        /// <param name="format">需要拼接的字符串</param>
        /// <param name="args">需要拼接的方法参数值列表</param>
        /// <returns></returns>
        string GetKey(string format, params object[] args);
        /// <summary>
        /// 拼接单个主键参数值
        /// </summary>
        /// <param name="format">需要拼接的字符串</param>
        /// <param name="primaryKey">主键</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        string GetSingleRootKey(string format, string primaryKey, object value);
        T TryGet<T>(string key, Func<T> func, TimeSpan? expiry = default) where T : class;

        T Get<T>(string key) where T : class;

        bool Add<T>(string key, T obj, TimeSpan? expiry = default);

        void AddAsync<T>(string key, T obj, TimeSpan? expiry = default);

        bool Delete(string key);

        void DeleteAsync(string key);

        bool Exists(string key);

        /// <summary>
        /// 向某个列表的右侧追加一条记录，右侧代表列表的最后，Key为某个列表的定义名称
        /// </summary>
        /// <typeparam name="T">添加的对象类型</typeparam>
        /// <param name="key">Key为某个列表的定义名称</param>
        /// <param name="obj">要添加的对象值</param>
        void ListRightPushAsync<T>(string key, T obj);

        /// <summary>
        /// 获取列表第一个值，Key为某个列表的定义名称
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="key">某个列表的定义名称</param>
        /// <returns></returns>
        T ListLeftPop<T>(string key);
        /// <summary>
        /// 发布一个订阅
        /// </summary>
        /// <typeparam name="T">发布订阅信息类型</typeparam>
        /// <param name="redisChannel">发布订阅的渠道名称</param>
        /// <param name="obj">发布订阅的信息内容</param>
        void Publish<T>(RedisChannel redisChannel, T obj);
        /// <summary>
        /// 消费一个订阅信息
        /// </summary>
        /// <typeparam name="T">发布订阅信息类型</typeparam>
        /// <param name="redisChannel">发布订阅的渠道名称</param>
        /// <param name="action">用来消费订阅信息的委托方法</param>
        void Subscriber<T>(RedisChannel redisChannel, Action<RedisChannel, RedisValue> action);
        /// <summary>
        /// 设置Key的过期时间
        /// </summary>
        /// <param name="redisKey">redisKey</param>
        /// <param name="expiry">过期时间的TimeSpan</param>
        void KeyExpireAsync(RedisKey redisKey, TimeSpan? expiry = default);
        /// <summary>
        /// 移除Key的过期时间
        /// </summary>
        /// <param name="redisKey">redisKey</param>
        void KeyPersistAsync(RedisKey redisKey);

        #region Redis服务器管理命令
        /// <summary>
        /// 清空 Redis 服务器的数据(删除数据库的所有 key )。
        /// 不填写databasesNo则清空所有数据库
        /// 此命令从不失败。
        /// <paramref name="databasesNo">数据库编号</paramref>
        /// </summary>
        void FlushAsync(int? databasesNo);
        /// <summary>
        /// 返回当前数据库的 key 的数量。
        /// <paramref name="databaseNo">数据库编号</paramref>
        /// </summary>
        Task<long> Size(int databaseNo = 0);
        /// <summary>
        /// 获取Redis服务器信息
        /// </summary>
        /// <param name="section">节点信息</param>
        /// <returns></returns>
        Task<IGrouping<string, KeyValuePair<string, string>>[]> Info(RedisValue? section);
        /// <summary>
        /// 获取redis服务器原始信息
        /// </summary>
        /// <param name="section">节点名称</param>
        /// <returns></returns>
        Task<string> InfoRaw(RedisValue? section);
        /// <summary>
        /// 批量删除多个前缀相同的key
        /// </summary>
        /// <param name="prefixKey">前缀Key</param>
        /// <param name="lauchScript">以脚本执行</param>
        void DeleteMultipleKey(string prefixKey, bool lauchScript);
        #endregion
    }
}
